﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MossmanMill.DataModel;
using MossmanMill.Properties;

namespace MossmanMill
{
    public partial class DataInputForm : Form
    {
        private bool rackTabLoaded, cardTabLoaded; //Tabs that are loaded
        private Point selectionLocation;
        private List<Card> availableCards;
        private Slottable selectedCard;
        private Sensor sensor;

        public DataInputForm()
        {
            InitializeComponent();
            var db = DatabaseAccess.Instance;
            availableCards = db.GetAvailableCards();
        }

        private void SetupRackTab(object sender, LayoutEventArgs e)
        {
            if (rackTabLoaded) return;
            rackTabLoaded = true;
            RackLocationField.Items.Clear();
            RackModelField.Items.Clear();
            var db = DatabaseAccess.Instance;
            var rooms = db.GetRooms();
            foreach (var room in rooms) RackLocationField.Items.Add(room);
            if (RackLocationField.Items.Count > 0) RackLocationField.SelectedIndex = 0;
            var rackModels = db.GetRackModels();
            foreach (var model in rackModels) RackModelField.Items.Add(model);
            previewRack = new Rack(-1, 0, "", "");
        }

        private void SetupCardTab(object sender, LayoutEventArgs e)
        {
            if (cardTabLoaded) return;
            cardTabLoaded = true;
            //Network Card
            NetworkCardConnection.Items.Clear();
            CardRackSelect.Items.Clear();
            SensorRackSelect.Items.Clear();
            var db = DatabaseAccess.Instance;
            foreach (var model in db.GetNetworkCardModels()) NetworkCardModel.Items.Add(model);
            NetworkCardConnection.Items.Add("Server");
            NetworkCardConnection.SelectedIndex = 0;
            var racks = db.GetRacks();
            foreach (var rack in racks)
            {
                SensorRackSelect.Items.Add(rack);
                CardRackSelect.Items.Add(rack); //All Cards
                NetworkCardConnection.Items.Add(rack);
            }

            /*****/
            SensorRackSelect.SelectedIndex = 0;
            CardRackSelect.SelectedIndex = 0;
            NetworkCardConnection.SelectedIndex = 0;
            CardSlotSelect.Slot = 8;
            ShowSlotContents(null, null);
            CardTypeFilter.SelectedIndex = 3;
            CardChannelFilter.SelectedIndex = 0;
            if (NetworkCardModel.Items.Count > 0) NetworkCardModel.SelectedIndex = 0;
            NetworkCardType.SelectedIndex = 0;
            sensorSlotSelect.Slot = 4;
            sensorChannelSelect.Channel = 3;
            /*****/

            //Processor
            ProcessorModel.Items.Clear();
            foreach (var model in db.GetProcessorModels()) ProcessorModel.Items.Add(model);

            /******/
            if (ProcessorModel.Items.Count > 0) ProcessorModel.SelectedIndex = 0;
            /******/

            //Card/IOModule
            SetupIOModules();
        }

        private void SetupIOModules()
        {
            var db = DatabaseAccess.Instance;
            availableCards = db.GetAvailableCards();
            bool typeFilter = CardTypeFilter.SelectedIndex != -1;
            bool chFilter = CardChannelFilter.SelectedIndex != -1;
            var type = typeFilter ? Card.GetCardType(CardTypeFilter.SelectedIndex) : CardType.OTHER;
            var channels = chFilter ? Int32.Parse(CardChannelFilter.SelectedItem.ToString()) :  -1;
            CardModel.Items.Clear();
            foreach (var card in availableCards)
            {
                //There's probably a better way to do this but it works
                bool match = false;
                if (!typeFilter && !chFilter) match = true;
                if ((!typeFilter && chFilter) && channels == card.GetChannels()) match = true;
                if ((typeFilter && !chFilter) && type == card.Type) match = true;
                if ((typeFilter && chFilter) && type == card.Type && channels == card.GetChannels()) match = true;
                if (match) CardModel.Items.Add(card);
            }
            /******/
            if (CardModel.Items.Count > 0) CardModel.SelectedIndex = 0;
            /******/
        }

        private void SwitchCardTab(object sender, TabControlEventArgs e)
        {
            if (e.TabPage.Text.Equals("Processor")) CardSlotSelect.IsProcessor = true;
            else CardSlotSelect.IsProcessor = false;
        }

        private void SubmitRoom(object sender, EventArgs e)
        {
            var name = RoomNameField.Text;
            var location = LocationField.Text;
            if (!string.IsNullOrEmpty(location) && !string.IsNullOrEmpty(name))
            {
                DatabaseAccess.Instance.AddRoom(name, location);
            }
            else
            {
                MessageBox.Show(Resources.FormValidationMsg);
            }
            //Let tabs update with new data
            cardTabLoaded = false;
            rackTabLoaded = false;
        }

        private void SubmitRack(object sender, EventArgs e)
        {
            var room = ((Room)RackLocationField.SelectedItem);
            var model = RackModelField.Text;
            var address = RackAddressField.Text;
            if (room == null || String.IsNullOrEmpty(model) || String.IsNullOrEmpty(address))
            {
                MessageBox.Show(Resources.FormValidationMsg);
                return;
            }
            var db = DatabaseAccess.Instance;
            db.AddRack(room.Id, model, address);
            //Let tabs update with new data
            cardTabLoaded = false;
            rackTabLoaded = false;
            RackModelField.Text = "";
            RackAddressField.Text = "";
            RackLocationField.SelectedIndex = -1;
        }

        private void SubmitNetworkCard(object sender, EventArgs e)
        {
            var db = DatabaseAccess.Instance;
            var model = NetworkCardModel.Text;
            if (String.IsNullOrEmpty(model) || NetworkCardType.SelectedIndex == -1 || CardRackSelect.SelectedIndex == -1)
            {
                MessageBox.Show(Resources.FormValidationMsg);
                return;
            }
            var rack = ((Rack)CardRackSelect.SelectedItem).Id;
            var slot = CardSlotSelect.Slot;
            var type = NetworkCardType.SelectedIndex == 0 ? 'U' : 'D';
            int conn = -1;
            if (NetworkCardConnection.SelectedIndex > 0)
            {
                Rack r = (Rack)NetworkCardConnection.SelectedItem;
                foreach (var card in r.Cards)
                {
                    if (card.SlotType == 'N' && ((NetworkCard)card).Type == 'D') 
                    {
                        conn = ((NetworkCard)card).NetworkId;
                        break;
                    }
                }
            }
            db.AddNetworkCard(rack, slot, model, type, conn);
            //Let tabs update with new data
            cardTabLoaded = false;
            rackTabLoaded = false;
            CardSlotSelect.Slot = (CardSlotSelect.Slot + 1)%12;
            NetworkCardModel.Text = "";
            NetworkCardType.SelectedIndex = -1;
            NetworkCardConnection.SelectedIndex = 0;
            SetupIOModules();
            ShowSlotContents(null, null);
        }

        private void SubmitProcessor(object sender, EventArgs e)
        {
            var db = DatabaseAccess.Instance;
            var model = ProcessorModel.Text;
            if (String.IsNullOrEmpty(model) || CardRackSelect.SelectedIndex == -1 || CardSlotSelect.Slot == 12)
            {
                MessageBox.Show(Resources.FormValidationMsg);
                return;
            }
            var rack = ((Rack)CardRackSelect.SelectedItem).Id;
            var pos = CardSlotSelect.Slot;
            db.AddProcessor(rack, pos, model);
            //Let tabs update with new data
            cardTabLoaded = false;
            rackTabLoaded = false;
            CardRackSelect.SelectedIndex = -1;
            CardSlotSelect.Slot = (CardSlotSelect.Slot + 1) % 12;
            ProcessorModel.Text = "";
            SetupIOModules();
            ShowSlotContents(null, null);
        }

        private void SubmitIOModule(object sender, EventArgs e)
        {
            var db = DatabaseAccess.Instance;
            if (CardRackSelect.SelectedIndex == -1 || CardModel.SelectedIndex == -1)
            {
                MessageBox.Show(Resources.FormValidationMsg);
                return;
            }
            var card = (Card)CardModel.SelectedItem;
            var rack = ((Rack)CardRackSelect.SelectedItem).Id;
            var pos = CardSlotSelect.Slot;
            if (CardSlotInfo.Text == "SPARE")
            {
                db.AddCard(rack,pos,card.ModuleId);
            }
            else
            {
                if (selectedCard.SlotType == 'C') db.ChangeCard(((Card)selectedCard).CardId, card.ModuleId);
                else
                {
                    db.DeleteSlottable(rack, pos);
                    db.AddCard(rack, pos, card.ModuleId);
                }
            }
            SetupIOModules();
            ShowSlotContents(null, null);
            CardInformation.Text = "";
        }

        private void SubmitSensor(object sender, EventArgs e)
        {
            var tag = sensorTag.Text.Normalize();
            var param = sensorParam.Text.Normalize();
            var desc = sensorDesc.Text.Normalize();
            var card = (Card) selectedCard;
            if (String.IsNullOrEmpty(tag) || String.IsNullOrEmpty(param) || String.IsNullOrEmpty(desc) || card == null)
            {
                MessageBox.Show(Resources.FormValidationMsg);
                return;
            }
            var db = DatabaseAccess.Instance;
            if (sensor == null)
            {
                db.AddSensor(new Sensor(-1,tag,param,desc,sensorChannelSelect.Channel, card.CardId));
                card.SetSensors(null);
            }
            else
            {
                db.updateSensor(sensor.Id, tag, param, desc);
                card.SetSensors(null);
            }
            ShowSlotContents(null, null);
            sensorChannelSelect.Invalidate();
        }

        private void MillMapClick(object sender, EventArgs e)
        {
            var point = (MouseEventArgs)e;
            selectionLocation = new Point(point.X, point.Y);
            LocationField.Text = point.X + "," + point.Y;
            MillMap.Invalidate();
        }

        private void MillMapDraw(object sender, PaintEventArgs e)
        {
            //7,15
            var pointer = Resources.MapPoint;
            e.Graphics.DrawImage(pointer, selectionLocation.X - 3, selectionLocation.Y - 30);
        }

        private void ApplyFilter(object sender, EventArgs e)
        {
            SetupIOModules();
        }

        private void ClearFilters(object sender, EventArgs e)
        {
            CardTypeFilter.SelectedIndex = -1;
            CardChannelFilter.SelectedIndex = -1;
            SetupIOModules();
        }

        private void ShowModuleInfo(object sender, EventArgs e)
        {
            CardInformation.Lines = ((Card)CardModel.SelectedItem).GetInfo();
        }

        private void ShowSlotContents(object sender, EventArgs e)
        {
            Rack rack = null;
            int slot = -1;
            int rackId = -1;
            TextBox info = null;
            if (tabs.SelectedIndex == 2)
            {
                //Switch tab helpfully
                if (CardSlotSelect.Slot == 0) CardTabControl.SelectedIndex = 1;
                if (CardSlotSelect.Slot > 3) CardTabControl.SelectedIndex = 0;

                rack = (Rack)CardRackSelect.SelectedItem;
                rackId = CardRackSelect.SelectedIndex;
                slot = CardSlotSelect.Slot;
                info = CardSlotInfo;
            } else if (tabs.SelectedIndex == 3)
            {
                rack = (Rack)SensorRackSelect.SelectedItem;
                rackId = SensorRackSelect.SelectedIndex;
                slot = sensorSlotSelect.Slot;
                info = sensorSlotInfo;
            }
            else info = CardSlotInfo;

            if (rackId == -1)
            {
                info.Text = "No Rack Selected";
                return;
            }

            var db = DatabaseAccess.Instance;
            var card = db.GetSlottable(rack.Id, slot, true);
            selectedCard = card;
            if (card == null)
            {
                info.Text = "SPARE";
                return;
            }
            sensorPanel.Enabled = card.SlotType == 'C';
            if (sensorPanel.Enabled && tabs.SelectedIndex == 3)
            {
                var c = (Card)card;
                sensorChannelSelect.setNumChannels(c.GetChannels());
                for (int i = 0; i < c.GetChannels(); i++)
                {
                    sensorChannelSelect.setHasSensor(i, c.Sensors[i] != null);
                }

                sensor = c.Sensors[sensorChannelSelect.Channel];
                if (sensor != null)
                {
                    sensorTag.Text = sensor.Tag;
                    sensorParam.Text = sensor.Param;
                    sensorDesc.Text = sensor.Desc;
                }
                else
                {
                    sensorTag.Text = "";
                    sensorParam.Text = "";
                    sensorDesc.Text = "";
                }
            }
            info.Lines = card.GetInfo();
        }

        private void PasteSensor(object sender, EventArgs e)
        {
            var split = ((TextBox)sender).Text.Split('\t');
            if (split.Length == 3)
            {
                sensorTag.Text = split[0];
                sensorParam.Text = split[1];
                sensorDesc.Text = split[2];
            }
        }

        private Rack previewRack, updateRack;

        private void drawRack(object sender, PaintEventArgs e)
        {
            if (previewRack == null) return;
            previewRack.draw(e.Graphics, 10, 10, 0.9f);
        }

        private void updatePreviewRack(object sender, EventArgs e)
        {
            if (previewRack == null) previewRack = new Rack(-1, 0, "", ""); 
            previewRack.SetRoom((Room)RackLocationField.SelectedItem);
            previewRack.SetModel(RackModelField.Text);
            previewRack.SetAddress(RackAddressField.Text);
            RackPreviewPanel.Invalidate();
        }

        public void LoadRoom(Room room)
        {
            RoomNameField.Text = room.Name;
            LocationField.Text = room.Location.X + "," + room.Location.Y;
            selectionLocation = room.Location;
            MillMap.Invalidate();
            tabs.SelectedIndex = 0;
        }

        public void LoadRack(Rack rack)
        {
            updateRack = rack;
            previewRack = rack;
            RackLocationField.SelectedItem = rack.Room;
            RackModelField.Text = rack.Model;
            RackAddressField.Text = rack.Address;
            CardRackSelect.SelectedItem = rack;
            SensorRackSelect.SelectedItem = rack;
            updatePreviewRack(null, null);
            LoadRoom(rack.Room);
            tabs.SelectedIndex = 1;
        }

        public void LoadCard(Card card)
        {
            LoadRack(card.Rack);
            CardModel.SelectedItem = card.Name;
            CardSlotSelect.Slot = card.Position;
            sensorSlotSelect.Slot = card.Position;
            CardTabControl.SelectedIndex = 0;
            CardTypeFilter.SelectedIndex = (int)card.Type;
            CardChannelFilter.SelectedItem = card.GetChannels();
            tabs.SelectedIndex = 2;
        }

        public void LoadSensor(Sensor sensor)
        {
            LoadCard(sensor.Card);
            sensorChannelSelect.Channel = sensor.Channel;
            sensorTag.Text = sensor.Tag;
            sensorParam.Text = sensor.Param;
            sensorDesc.Text = sensor.Desc;
            tabs.SelectedIndex = 3;
        }
    }
}
